package org.atlantis.grosbeak.depot.loader;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.atlantis.grosbeak.depot.DepotException;
import org.atlantis.grosbeak.depot.DepotLoader;
import org.atlantis.grosbeak.depot.DepotUtils;
import org.atlantis.grosbeak.depot.desc.ObjectDesc;
import org.atlantis.grosbeak.json.Jsons;
import org.atlantis.grosbeak.lang.Exceptions;

/**
 * 从一个Map中解析出对象。
 * 
 * @author <a href="mailto:seenoevil.cn@gmail.com">SeeNoEvil</a>
 * 
 */
@SuppressWarnings("unchecked")
public class MapLoader implements DepotLoader {

	private Map<String, Map<String, Object>> map;

	/**
	 * 实例化一个MapLoader。默认用于配置的Map是一个空的HashMap。
	 */
	protected MapLoader() {
		map = new HashMap<String, Map<String, Object>>();
	}

	/**
	 * 通过一个Json格式的字符串（程序会自动把这个Json格式的字符串，通过Jsons工具转换成一个Map），来实例化一个MapLoader。
	 * 
	 * @param jsonConfig
	 *            Json格式的字符串。
	 */
	public MapLoader(String jsonConfig) {
		this((Map<String, Map<String, Object>>) Jsons.fromJson(jsonConfig));
	}

	/**
	 * 通过一个用于配置的Map来实例化一个MapLoader。
	 * 
	 * @param map
	 *            包含配置信息的Map。
	 */
	public MapLoader(Map<String, Map<String, Object>> map) {
		this.map = map;
	}

	/**
	 * 获得用于配置的Map。
	 * 
	 * @return 包含配置信息的Map。
	 */
	public Map<String, Map<String, Object>> getMap() {
		return map;
	}

	/**
	 * 设定用于配置的Map。
	 * 
	 * @param map
	 *            包含配置信息的Map。
	 */
	public void setMap(Map<String, Map<String, Object>> map) {
		this.map = map;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.atlantis.grosbeak.depot.DepotLoader#getIds()
	 */
	public String[] getIds() {
		return map.keySet().toArray(new String[map.size()]);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.atlantis.grosbeak.depot.DepotLoader#has(java.lang.String)
	 */
	public boolean has(String id) {
		return map.containsKey(id);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.atlantis.grosbeak.depot.DepotLoader#load(java.lang.String)
	 */
	public ObjectDesc load(String id) throws DepotException {
		Map<String, Object> m = map.get(id);
		if (null == m)
			throw Exceptions.makeThrow(DepotException.class,
					"Unable to find the '%s' object.", id);
		Object parentStr = m.get("parent");
		// 如果当前对象有“parent”
		if (null != parentStr) {
			ObjectDesc parent = load(parentStr.toString());
			Map<String, Object> selfMap = new HashMap<String, Object>();
			for (Entry<String, Object> entry : m.entrySet()) {
				if ("parent".equals(entry.getKey()))
					continue;
				selfMap.put(entry.getKey(), entry.getValue());
			}
			ObjectDesc self = DepotUtils.mapToObjectDesc(selfMap);
			return DepotUtils.merge(self, parent);
		}
		return DepotUtils.mapToObjectDesc(m);
	}
}
